home *** CD-ROM | disk | FTP | other *** search
/ TOS Silver 2000 / TOS Silver 2000.iso / programm / MM2_DEV / S / MOS / KBDEVENT.I < prev    next >
Encoding:
Modula Implementation  |  1993-10-29  |  29.2 KB  |  707 lines

  1. IMPLEMENTATION MODULE KbdEvents;
  2. (*$R-,S- Stacküberprüfung muß ausgeschaltet sein !!*)
  3. (*$Y+*)
  4.  
  5. (*------------------------------------------------------------------------------
  6.  * Version 2.6  (für MEGAMAX MOS 2.2)
  7.  *------------------------------------------------------------------------------
  8.  * Copyright (c) 1989, 90, 91 by Michael Seyfried
  9.  *------------------------------------------------------------------------------
  10.  *                              Implementierungshinweise
  11.  *
  12.  * Die Routinen 'afterTrap2','Trap2Handler','IKBDHandler' und 'EtvTimerHandler'
  13.  * mußten wegen besonderer Anforderungen in Assembler codiert werden. Ich habe
  14.  * mich bemüht, die Routinen so gut wie möglich zu kommentieren.
  15.  * Damit der Fehler beim AES behoben werden kann wird 'Trap2Handler' auf den
  16.  * TRAP2-Vektor installiert. Diese Routine sorgt dann dafür, daß nach einem
  17.  * Aufruf von 'evnt_keyboard' oder 'evnt_multi' vor der Rückkehr zum Aufrufer
  18.  * 'afterTrap2' aufgerufen wird.
  19.  * 'OverflowHandler' verhindert ein Tastaturüberlauf über 'BufferKeyPtr' hinaus.
  20.  * Dazu wird er über die Vektoren 'IKBD' und 'etv_timer' angesprungen.
  21.  *------------------------------------------------------------------------------
  22.  * 11.08.89   2.0   Fertigstellung der Version 2.0
  23.  * 13.08.89   2.1   Falls ein Prozeß 'evnt_multi' ruft, wird nur dann
  24.  *                  'Trap2Handler' angesprungen, wenn auch auf ein Tastatur-
  25.  *                  ereignis gewartet wird.
  26.  * 14.08.89   2.1a  Bug in Trap2Handler behoben. 'evnt_multi' wurde nur
  27.  *                  behandelt, wenn man auf ein MAUSEREIGNIS wartete.
  28.  * 15.08.89   2.1b  Es werden nun alle Register gerettet, weil der Orginal-
  29.  *                  dispatcher das auch macht.
  30.  * 15.08.89   2.2   WriteToAppl gestrichen, weil unnötig, wenn dieses Modul
  31.  *                  sich mit SysInitGem anmeldet und vor ExitGem die Vektoren
  32.  *                  restauriert.
  33.  * 19.08.89   2.2a  Die Vektoren werden nun nicht mehr mit den Prozeduren aus
  34.  *                  dem Modul 'XBRA' verändert. Es ist nun ein lokales Modul
  35.  *                  'xbra' vorhanden, das spezielle Prozeduren für (Assembler-)
  36.  *                  Routinen enthält, die schon einen XBRA-Header haben.
  37.  * 01.09.89   2.3   'LookAESKeys' und 'AESShift' wurden entfernt. Fehler bei der
  38.  *                  Syncronisation behoben. Modul installiert sich nun nicht
  39.  *                  mehr automatisch.
  40.  * 17.09.89   2.4   Syncronisation korrigiert. Rechner 'hängt' nicht mehr bei
  41.  *                  Überlauf des Puffers über BufferKeyPtr.
  42.  * 02.05.90         Anpassung an Compiler 3.8, $Y+ vorn eingefügt
  43.  * 25.11.90   2.5   TT: InitApplication statt InitGem-Aufruf, TRAP #6 statt
  44.  *                  RaiseError-Aufruf
  45.  * 15.02.91   2.6   Fehler bei der Tastatursyncronisation behoben.
  46.  *------------------------------------------------------------------------------
  47.  *)
  48.  
  49. FROM SYSTEM IMPORT ASSEMBLER, ADDRESS, ADR, WORD;
  50.  
  51. FROM MOSGlobals IMPORT MemArea, OutOfMemory;
  52.  
  53. FROM XBIOS IMPORT IORECPTR, IORec, Keyboard;
  54.  
  55. FROM ResCtrl IMPORT RemovalCarrier, CatchRemoval;
  56.  
  57. FROM SysUtil2 IMPORT ModeBuf, EnterSupervisorMode, LeaveSupervisorMode;
  58.  
  59. FROM SysTypes IMPORT AnyLongType, BBS;
  60.  
  61. FROM SysVars IMPORT etv_timer, conterm;
  62.  
  63. FROM GEMEnv IMPORT GemHandle, SysInitApplication, ExitGem, CurrGemHandle;
  64.  
  65. IMPORT GEMShare;
  66.  
  67.  
  68. CONST KbShiftBit        = 3;      (* wichtige Bits in Conterm               *)
  69.       KbRepeatBit       = 1;      (*           "                            *)
  70.       HighTrap2PBList   = 25;     (* "Beschränkung" auf 25 Prozesse         *)
  71.       XBRAID            = "KbEv"; (* Übereinstimmung mit den Prozeduren !!  *)
  72.       TRAP2             = $088L;  (* Adresse des TRAP2-Vektors              *)
  73.       IKBD              = $118L;  (* Adresse des IKBD-Vektors               *)
  74.       JMPInstr          = $4EF9;  (* Code für JMP     $xxxxxxxx             *)
  75.       MOVEToStackInstr  = $2F3C;  (* Code für MOVE.L  #$xxxxxxxx, -(SP)     *)
  76.  
  77. TYPE  PtrAnyLongType  = POINTER TO AnyLongType;
  78.  
  79.       (* Trap2 Parameter Block *)
  80.       PtrTrap2PB      = POINTER TO Trap2PB;
  81.       Trap2PB         = RECORD
  82.                           AESNo: CARDINAL;          (* AES-Funktionsnummer *)
  83.                           AddrINTOUT: ADDRESS;      (* Adr. von IntOut *)
  84.                           ReturnAddr: ADDRESS;      (* Returnadr. nach TRAP2 *)
  85.                           moveToStackInstr: WORD;   (* MOVE.L #PBAddr, -(SP) *)
  86.                           PBAddr: ADDRESS;          (* Adr. auf dieses Feld *)
  87.                           jmpInstr: WORD;           (* JMP afterTrap2 *)
  88.                           AfterTrap2Addr: ADDRESS;  (* Adr. von afterTrap2 *)
  89.                         END;
  90.  
  91. VAR   IoRecPtr: IORECPTR;           (* Zeiger auf IOREC-Struktur der Tastatur *)
  92.       IbufPlusIbufsize: ADDRESS;    (* IoRec.ibuf + IoRec.ibufsize *)
  93.       BufferKeyPtr: PtrAnyLongType; (* Ptr. auf akt. AES-Zeichen im Kbd-Buffer*)
  94.       BufferKeyValid: BOOLEAN;      (* TRUE, wenn BufferKeyPtr gültig *)
  95.  
  96.       rCarrier: RemovalCarrier;     (* Für ordentliche Prozeßbeendingung *)
  97.  
  98.       (* Systemvariablen *)
  99.       Conterm   [conterm]   : BBS;
  100.  
  101.       (* Speicher für alte und neue Werte *)
  102.       oldConterm: BBS;
  103.  
  104.       (* In dieser Liste werden für jeden Prozeß, der 'evnt_timer' oder
  105.        * 'evnt_keyboard' gerufen hat, wichtige Daten zwischengespeichert.
  106.        * Die nicht belegten Listeneinträge werden über 'Trap2PBFree' und
  107.        * untereinander über 'AddrINTOUT' verkettet.
  108.        *)
  109.       Trap2PBList     : ARRAY [0..HighTrap2PBList] OF Trap2PB;
  110.       Trap2PBFree     : PtrTrap2PB;     (* Zeiger auf unbenutzte Elemente *)
  111.  
  112.       (* Flags, die anzeigen, welche Vektoren DIESES Modul installiert hat *)
  113.       TRAP2VecInstalled    : BOOLEAN;
  114.       IKBDVecInstalled     : BOOLEAN;
  115.       EtvTimerVecInstalled : BOOLEAN;
  116.  
  117.       (* GEM-Handle dieses Moduls *)
  118.       GEMHandle: GemHandle;
  119.  
  120.  
  121. MODULE xbra;
  122. (*
  123.  * Dieses Modul enthält Prozeduren, mit deren Hilfe man (Assembler-) Routinen,
  124.  * die bereits einen XBRA-Header enthalten, auf Vektoren installieren, bzw.
  125.  * installierte Routinen entfernen kann.
  126.  * Alle Prozeduren dürfen nur im Supervisor-Mode aufgerufen werden !!
  127.  * Nach Vorschlägen von Thomas Tempelmann.
  128.  *)
  129.  
  130. IMPORT ASSEMBLER, ADDRESS;
  131.  
  132. EXPORT  ID, install, installed, remove;
  133.  
  134.  
  135. TYPE ID = ARRAY [0..3] OF CHAR;   (* Typ für xb_id *)
  136.  
  137.  
  138. (*$L- Parameter linking aus für das ganze lokale Modul*)
  139.  
  140.   PROCEDURE install( xbraProc: PROC; vec: ADDRESS);
  141.   (*
  142.    * Eingabe: (Assembler-) Routine mit XBRA-Header und Vektor
  143.    * Effekt:  Die Routine wird auf den angegebenen Vektor installiert. Dabei
  144.    *          wird der alte Vektor gemäß XBRA-Standard in den XBRA-Header der
  145.    *          Prozedur xbraProc gerettet.
  146.    * Beachte: Diese Routine überprüft nicht, ob xbraProc bereits auf den Vektor
  147.    *          installiert ist. Dazu dient die folgende Prozedur 'installed'.
  148.    *)
  149.     BEGIN
  150.       ASSEMBLER
  151.           MOVE    SR,D2
  152.           ORI     #$0700,SR
  153.           MOVE.L  -(A3), A0       ; Vektoradresse vom Param.-Stack holen
  154.           MOVE.L  -(A3), A1       ; Adresse von xbraProc vom Param.-Stack holen
  155.           LEA     12(A1), A1      ; entry berechnen
  156.           MOVE.L  (A0),-4(A1)     ; alten Vektor retten (in XBRA-Struktur)
  157.           MOVE.L  A1,(A0)         ; Vektor auf entry verbiegen
  158.           MOVE    D2,SR
  159.       END
  160.     END install;
  161.  
  162.   PROCEDURE installed( name: ID; vec: ADDRESS): BOOLEAN;
  163.   (*
  164.    * Eingabe: XBRA-Kennung und Vektor
  165.    * Wert:    TRUE, genau dann wenn auf den Vektor eine Routine mit der ange-
  166.    *          gebenen XBRA-Kennung installiert ist.
  167.    *)
  168.     BEGIN
  169.       ASSEMBLER
  170.               MOVE    SR,D2
  171.               ORI     #$0700,SR
  172.               MOVE.L  -(A3), A0             ; Vektoradresse nach A0
  173.               MOVE.L  -(A3), A2             ; XBRA-Kennung nach A2
  174.            l: MOVE.L  (A0),A1
  175.               CMPI.L  #$58425241,-12(A1)    ; Ist dies ein XBRA-Eintrag?
  176.               BNE     n                     ; Nein -> nicht gefunden
  177.               CMPA.L  -8(A1), A2            ; Kennung gleich ?
  178.               BEQ     f                     ; Ja -> gefunden
  179.               LEA     -4(A1),A0             ; Vorige Vektoradr. nach A0
  180.               BRA     l
  181.            n: MOVE.W  #FALSE, (A3)+
  182.               BRA     fin
  183.            f: MOVE.W  #TRUE, (A3)+
  184.          fin: MOVE    D2,SR
  185.       END
  186.     END installed;
  187.  
  188.   PROCEDURE remove( xbraProc: PROC; vec: ADDRESS);
  189.   (*
  190.    * Eingabe: XBRA-Routine und Vektor
  191.    * Effekt:  Die angegebene Routine wird, falls installiert, aus der auf vec
  192.    *          installierten Vektorenkette ausgeklinkt. Der alte Vektor wird
  193.    *          restauriert.
  194.    * Beachte: Diese Routine darf nur aufgerufen werden, wenn man sicher ist,
  195.    *          daß die Routine xbraProc auf dem angegebenen Vektor installiert
  196.    *          war (ist), weil auf jeden Fall der alte Vektor (im XBRA-Header
  197.    *          von xbraProc) restauriert wird. Dies wird deshalb so gehandhabt,
  198.    *          da es immer noch viele Programme gibt, die Vektoren nicht nach
  199.    *          dem XBRA-Verfahren verbiegen.
  200.    *)
  201.     BEGIN
  202.       ASSEMBLER
  203.           MOVE    SR,D2
  204.           ORI     #$0700,SR
  205.           MOVE.L  -(A3), A0             ; Vektoradresse holen
  206.           MOVE.L  -(A3), A2             ; Adresse von xbraProc holen
  207.           LEA     12(A2), A2            ; entry berechnen
  208.        l: MOVE.L  (A0),A1
  209.           CMPA.L  A2,A1                 ; 'entry' gefunden?
  210.           BEQ     f
  211.           CMPI.L  #$58425241,-12(A1)    ; Ist dies ein XBRA-Eintrag?
  212.           BNE     n                     ; Nein -> entry hier trotzdem austragen
  213.           LEA     -4(A1),A0             ; Vorige Vektoradr. nach A0
  214.           BRA     l
  215.        n: MOVE.L  A2,A1
  216.        f: MOVE.L  -4(A1),(A0)           ; Entry.old eintragen
  217.           MOVE    D2,SR
  218.       END
  219.     END remove;
  220.  
  221. (*$L= Parameter linking wieder ein*)
  222.  
  223. END xbra;
  224.  
  225.  
  226. PROCEDURE FlushKbd;
  227. (*
  228.  * Effekt: Der AES-Puffer und Tastaturpuffer werden gelöscht.
  229.  *)
  230.   BEGIN
  231.     pubs^.aINTIN[0]:= 33;          (* ev_mflags:= {keyboard, timer} *)
  232.     pubs^.aINTIN[14]:= 0;          (* ev_mtlocount:= 0              *)
  233.     pubs^.aINTIN[15]:= 0;          (* ev_mthicount:= 0              *)
  234.     REPEAT
  235.       aes_if( 25)                 (* evnt_multi                    *)
  236.     UNTIL pubs^.aINTOUT[0] = 32    (* UNTIL ev_mwhich = {timer}     *)
  237.   END FlushKbd;
  238.  
  239. PROCEDURE SyncBuffer;
  240. (*
  241.  * Effekt:  BufferKeyPtr und HighBufferKey werden mit dem AES-Puffer
  242.  *          syncronisiert. Dazu wird der AES-Buffer gelöscht.
  243.  *)
  244.   BEGIN
  245.     WITH IoRecPtr^ DO
  246.       BufferKeyPtr:= ibuf + LONG (ibuftl);
  247.       BufferKeyValid:= TRUE;
  248.     END;
  249.   END SyncBuffer;
  250.  
  251. (*$L- Parameter linking aus*)
  252. PROCEDURE afterTrap2;
  253. (*
  254.  * Diese Routine wird bei der Rückkehr aus einer der Routinen 'evnt_keyboard'
  255.  * bzw. 'evnt_multi' aufgerufen. Sie setzt dann 'BufferKeyPtr' auf das richtige
  256.  * Zeichen im Tastaturpuffer und kehrt zum Aufrufer, i.A. dem Anwenderprogramm,
  257.  * zurück.
  258.  * Der letzte Punkt ist aber gar nicht so einfach, wie man glaubt. Denn auch
  259.  * Accessorys rufen 'evnt_multi'. Es reicht also bei weitem nicht aus, die
  260.  * Rücksprungadresse in einer globalen Variablen zwischenzuspeichern. Auch die
  261.  * Verwendung eines Stacks zum Ablegen dieser Adressen ist unmöglich, da beim
  262.  * Pseudo-Multitasking die Reihenfolge der Aufrufe von evnt_multi nicht immer
  263.  * mit der Reihenfolge der Rücksprünge aus diesen Routinen übereinstimmt.
  264.  * Zur Lösung diese Problems wird von 'Trap2Handler' für jeden Prozeß, der
  265.  * 'evnt_keyboard' oder 'evnt_multi' aufruft, ein Parameterblock angelegt, in
  266.  * dem einige Daten und die Rücksprungadresse abgelegt werden. Außerdem steht
  267.  * in diesem Parameterblock eine JMP-Anweisung auf 'afterTrap2'. Vor dieser JMP-
  268.  * Anweisung steht ein Befehl, der die Adresse dieses PB in Register A0
  269.  * schreibt. 'Trap2Handler' sorgt dafür, daß bei der Rückkehr aus einer AES-
  270.  * Routine über diese Anweisungen 'afterTrap2' aufgerufen wird. Durch die
  271.  * Adresse des PB in A0 erhält diese Routine so alle Daten und die richtige
  272.  * Rücksprungadresse.
  273.  * Vor dem Rücksprung zum Aufrufer wird in 'int_out[ 4] der Tastaturzustand bei
  274.  * Tastendruck geschrieben. So liefert nun 'AESEvents.MultiEvent' den Status
  275.  * der Sondertasten richtig zurück.
  276.  *
  277.  * Es werden alle Register gerettet !
  278.  *)
  279.   BEGIN
  280.     ASSEMBLER
  281.                       ; Bei Eintritt steht auf dem Stack die Adresse des
  282.                       ; zugehörigen Parameter Blocks
  283.  
  284.                       ; Erstmal die benötigten Register retten:
  285.                       MOVEM.L D0-D2/A0-A2, -(SP)
  286.  
  287.                       ; Parameter holen:
  288.                       MOVE.L  24(SP), A0              ; Adresse des PB holen
  289.                       MOVE.W  (A0), D0                ; AES-Fktnr. nach D0
  290.                       MOVE.L  2(A0), A1               ; Adresse INTIN
  291.                       MOVE.L  6(A0), 24(SP)           ; Rückadr. auf Stack
  292.  
  293.                       ; PB in Free-Liste einfügen
  294.                       MOVE.L  Trap2PBFree, 2(A0)      ; über 'AddrINTOUT' verk.
  295.                       MOVE.L  A0, Trap2PBFree
  296.  
  297.                       TST.W   BufferKeyValid          ; BufferKeyPtr gültig ?
  298.                       BEQ     return                  ; Nein->Nichts veranlassen
  299.  
  300.                       ; Falls vorhanden, Zeichen in D1 ermitteln
  301.                       MOVE.W  (A1), D1                ; D1:= int_out[ 0]
  302.                       CMPI.W  #20, D0                 ; evnt_keyboard ?
  303.                       BEQ     lookKey                 ; => Zeichen in D1
  304.  
  305.                       ; bei evnt_multi schauen, ob Taste ansteht
  306.                       ; => ev_mwhich in D1
  307.                       BTST    #0, D1                  ; Tastaturereignis ?
  308.                       BEQ     return                  ; falls nicht => ret
  309.                       MOVE.W  10(A1), D1              ; sonst Zeichen aus
  310.                                                       ; int_out[ 5] nach D1
  311.  
  312.                       ; entsprechendes Zeichen im Tastaturpuffer "suchen"
  313.                       ; Initialisierungen:
  314.         lookKey:      MOVE.L  IoRecPtr, A0            ; Adr IoRec nach A0
  315.                       MOVE.W  8(A0), D0               ; D0:= ibuftl
  316.                       EXT.L   D0
  317.                       ADD.L   (A0), D0                ; D0 = ibuf + ibuftl
  318.                       ADDQ.L  #4, D0                  ; INC( D0, 4)
  319.                       MOVE.L  IbufPlusIbufsize, A2    ; höchster Wert+1 nach A2
  320.                       CMP.L   A2, D0                  ; D0 >= A2 ?
  321.                       BLT     lookBuffer              ; falls nein, ok
  322.                       MOVE.L  (A0), D0                ; sonst korrigieren
  323.  
  324.         lookBuffer:   MOVE.L  BufferKeyPtr, A0        ; Zeiger auf Puffer holen
  325.  
  326.         nextKey:      ; A0:= (A0 + 4) MOD A2
  327.                       ADDQ.L  #4, A0                  ; BufferKeyPtr erhöhen
  328.                       CMPA.L  A2, A0                  ; A0 >= A2 ?
  329.                       BLT     getKey                  ; nein
  330.                       MOVE.L  IoRecPtr, A0            ; Adr IoRec holen
  331.                       MOVE.L  (A0), A0                ; A0:= ibuf
  332.  
  333.         getKey        CMPA.L  D0, A0                  ; BufferKeyPtr = ibuftl+4?
  334.                       BEQ     notFound                ; falls ja nicht gefunden
  335.                       MOVE.L  (A0), D2                ; Taste aus Puffer holen
  336.                       CMP.B   D1, D2                  ; ASCII-Codes gleich ?
  337.                       BNE     nextKey                 ; wenn nein nochmal
  338.                       SWAP    D2                      ; scan-Code in low-Byte
  339.                       ROR.W   #8, D1                  ; scan-Code in low-Byte
  340.                       CMP.B   D1, D2                  ; Scan-Codes gleich ?
  341.                       BEQ     found                   ; wenn ja, dann fertig
  342.                       ROR.W   #8, D1                  ; wieder scan,ascii
  343.                       BRA     nextKey                 ; nochmal
  344.  
  345.                       ; Zeichen wegen Pufferüberlauf nicht mehr im Puffer
  346.         notFound:     CLR.W   BufferKeyValid          ;BufferKeyPtr nicht gültig
  347.                       BRA     return
  348.  
  349.                       ; Zeichen gefunden => Kbshift in int_out[ 4] schreiben
  350.         found:        MOVE.L  A0, BufferKeyPtr        ; BufferKeyPtr sichern
  351.                       LSR.W   #8, D2                  ; Kbshift in low-Byte
  352.                       MOVE.W  D2, 8(A1)               ; nach int_out[ 4]
  353.  
  354.         return:       ; Zum Aufrufer der AES-Routine (TRAP2) zurückkehren
  355.                       MOVEM.L (SP)+, D0-D2/A0-A2      ; Regs restaurieren
  356.  
  357.                       ; nun steht die Rücksprungadresse auf dem Stack und
  358.                       ; RTS kehrt zurück.
  359.     END
  360.   END afterTrap2;
  361. (*$L=*)
  362.  
  363. (*$L- Parameter linking aus*)
  364. PROCEDURE Trap2Handler;
  365. (*
  366.  * Diese Routine ist auf den TRAP2-Vektor installiert und wird daher bei
  367.  * jedem AES oder VDI-Aufruf angesprungen. Zunächst wird dann getestet,
  368.  * ob ein AES-Aufruf (D0 = 200) vorliegt. Ist dies der Fall, dann wird
  369.  * nachgefragt, ob evnt_keyboard (AES 20) oder evnt_multi (AES 25) auf-
  370.  * gerufen wurde. Falls nicht, wird nichts weiter veranlasst und die vorher-
  371.  * gehende TRAP2-Routine wird ausgeführt.
  372.  * Im anderen Fall wird ein Parameter Block angelegt, der die AES-Funktions-
  373.  * nummer, die Adresse des int_in-Arrays und die Rücksprungadresse enthält.
  374.  * Bei Modulinitialisierung wurden Anweisungen in diesen PB geschrieben, die
  375.  * 'afterTrap2' mit der Adresse dieses PB als Parameter in A0 aufrufen.
  376.  * Der Wert des PC auf dem SSP-Stack wird dann so verändert, daß nach Rückkehr
  377.  * aus dem AES über diese Anweisungen 'afterTrap2' aufgerufen wird.
  378.  *
  379.  * Es werden alle Register gerettet !
  380.  *)
  381.   BEGIN
  382.     ASSEMBLER
  383.                       ; XBRA-Header
  384.                       ASC     "XBRA"              ; xb_magic
  385.                       ASC     "KbEv"              ; xb_id
  386.       xb_oldvec:      DC.L    0                   ; wird von install gesetzt
  387.  
  388.                       ; hier ist die Einsprungadresse
  389.                       ; feststellen, ob evnt_keyboard oder evnt_multi
  390.                       ; aufgerufen wurde:
  391.       entry:          CMPI.W  #200, D0            ; AES-Aufruf ?
  392.                       BNE.W   callPreviousV
  393.  
  394.                       ; AES-Aufruf => erstmal die benötigten Register retten
  395.                       MOVEM.L D2/A1-A3, -(SP)
  396.                       EXG.L   D1, A0              ; AESPB nach A0
  397.  
  398.                       MOVE.L  (A0), A1            ; Adresse von control([0])
  399.                       MOVE.W  (A1), A2            ; Opcode für AES nach A2
  400.                       CMPA.W  #20, A2             ; evnt_keyboard ?
  401.                       BEQ     useAfterTrap2
  402.                       CMPA.W  #25, A2             ; evnt_multi ?
  403.                       BNE     restore
  404.  
  405.                       ; falls evnt_multi, feststellen, ob überhaupt auf ein
  406.                       ; Tastaturereignis gewartet wird.
  407.                       MOVE.L  8(A0), A1           ; Adresse von int_in([0])
  408.                       MOVE.W  (A1), D2            ; D2:= ev_mflags
  409.                       BTST    #0, D2              ; keyboard IN ev_mflags ?
  410.                       BEQ     restore             ; nein => alte Rotine
  411.  
  412.                       ; falls BufferKeyPtr nicht gültig, Puffer syncronisieren
  413.       useAfterTrap2:  TST.W   BufferKeyValid      ; BufferKeyPtr gültig ?
  414.                       BNE     createPB            ; Ja -> weiter
  415.  
  416.                       ; BufferKeyPtr ist nicht gültig => neu syncronisieren
  417.                       LEA     stack(PC), A3         ; A3-Stack anlegen
  418.                       MOVEM.L D0-D1/A0/A2, -(SP)    ; benötigte Register retten
  419.                       JSR     SyncBuffer            ; Puffer leeren u. sync.
  420.                       MOVEM.L (SP)+, D0-D1/A0/A2    ; Register restaurieren
  421.                       MOVE.W  #TRUE, BufferKeyValid ; BufferKeyValid:= TRUE
  422.  
  423.                       ; Trap2PB anlegen
  424.       createPB:       MOVE.L  Trap2PBFree, A1     ; Adr. vom freien Listenel.
  425.                       MOVE.L  2(A1), Trap2PBFree  ; aus FreeList ausketten
  426.                       MOVE.W  A2, (A1)+           ; AES-Nr. ablegen
  427.                       MOVE.L  12(A0), (A1)+       ; Adr. INTOUT ablegen
  428.                       MOVE.L  18(SP), (A1)+       ; Return-Adresse ablegen
  429.                       MOVE.L  A1, 18(SP)          ; n. ret. über PB afterTrap2
  430.  
  431.                       ; Register restaurieren
  432.       restore:        MOVEM.L (SP)+, D2/A1-A3
  433.                       EXG.L   A0, D1
  434.  
  435.                       ; alte Trap2-Routine aufrufen
  436.       callPreviousV:  MOVE.L  xb_oldvec(PC), -(SP)  ; alten Vektor auf Stack
  437.  
  438.                       ; Auf dem Stack steht nun der alte Vektor. Dieser wird
  439.                       ; durch RTS angesprungen.
  440.                       RTS
  441.  
  442.       stack:          DS      2000                   ; 500 Bytes Stack
  443.     END
  444.   END Trap2Handler;
  445. (*$L=*)
  446.  
  447. (*$L- Parameter linking aus*)
  448. PROCEDURE OverflowHandler;
  449. (*
  450.  * Diese Routine überwacht, ob 'IoRec.ibuf' + 'IoRec.head' 'BufferKeyPtr'
  451.  * "überholt".
  452.  *
  453.  * Es werden alle Register gerettet !!
  454.  *)
  455.   BEGIN
  456.     ASSEMBLER
  457.                       ; Einsprungadresse
  458.                       ; Alter Vektor steht bei Eintritt auf dem Stack
  459.  
  460.                       ; Testen, ob Puffer übergelaufen war
  461.                       TST.W   BufferKeyValid
  462.                       BEQ     callPreviousV         ; JA->alte Routine
  463.  
  464.                       MOVEM.L A0-A1/D0-D1, -(SP)    ; benötigte Register retten
  465.  
  466.                       ; D0:= ibuf + ((ibufhd + 4L) MOD ibufsize)
  467.                       MOVE.L  IoRecPtr, A0          ; Adr. IoRec holen
  468.                       MOVE.W  6(A0), D0             ; D0:= ibufhd
  469.                       EXT.L   D0                    ; Longword daraus machen
  470.                       ADD.L   (A0), D0              ; D0:= ibuf + ibufhd
  471.                       ADDQ.L  #4, D0                ; INC( D0, 4)
  472.                       MOVE.L  IbufPlusIbufsize, D1  ; D1:= ibuf + ibufsize
  473.                       CMP.L   D1, D0                ; D0 < D1?
  474.                       BLT     compare1
  475.                       MOVE.L  (A0), D0              ; evt. korrigieren D0=ibuf
  476.  
  477.                       ; hat head+4 den BufferKeyPtr erreicht ?
  478.       compare1:       CMP.L   BufferKeyPtr, D0      ; D0 = BufferKeyPtr ?
  479.                       BEQ     BufferOverflow        ; JA->Überlauf
  480.  
  481.                       ; D0:= ibuf + ((ibufhd + 8L) MOD ibufsize)
  482.                       ADDQ.L  #4, D0
  483.                       CMP.L   D1, D0                ; D0 < D1?
  484.                       BLT     compare2
  485.                       MOVE.L  (A0), D0              ; evt. korrigieren D0=ibuf
  486.  
  487.                       ; hat head+8 den BufferKeyPtr erreicht ? (wegen Protos)
  488.       compare2:       CMP.L   BufferKeyPtr, D0      ; D0 = BufferKeyPtr?
  489.                       BNE     restore               ; Nein->alte Routine
  490.  
  491.       BufferOverflow: CLR.W   BufferKeyValid        ; BufferKeyPtr nicht gültig
  492.  
  493.                       ; alte Routine aufrufen
  494.       restore:        MOVEM.L (SP)+, A0-A1/D0-D1    ; Register restaurieren
  495.  
  496.                       ;nun wird über RTS der alte Vektor angesprungen !!!
  497.       callPreviousV:  RTS
  498.     END
  499.   END OverflowHandler;
  500. (*$L=*)
  501.  
  502. (*$L- Parameter linking aus*)
  503. PROCEDURE IKBDHeader;
  504. (*
  505.  * XBRA-Header für IKBD-Routine
  506.  *)
  507.   BEGIN
  508.     ASSEMBLER
  509.                       ; XBRA-Header
  510.                       ASC     "XBRA"                ; xb_magic
  511.                       ASC     "KbEv"                ; xb_id
  512.       xb_oldvec:      DC.L    0                     ; wird von install gesetzt
  513.  
  514.                       ; Einsprungadresse
  515.                       MOVE.L  xb_oldvec(PC), -(SP)  ; Alter Vektor auf Stack
  516.                       JMP     OverflowHandler       ; OverflowHandler rufen
  517.     END
  518.   END IKBDHeader;
  519. (*$L=*)
  520.  
  521. (*$L- Parameter linking aus*)
  522. PROCEDURE EtvTimerHeader;
  523. (*
  524.  * XBRA-Header für IKBD-Routine
  525.  *)
  526.   BEGIN
  527.     ASSEMBLER
  528.                       ; XBRA-Header
  529.                       ASC     "XBRA"                ; xb_magic
  530.                       ASC     "KbEv"                ; xb_id
  531.       xb_oldvec:      DC.L    0                     ; wird von install gesetzt
  532.  
  533.                       ; Einsprungadresse
  534.                       MOVE.L  xb_oldvec(PC), -(SP)  ; Alter Vektor auf Stack
  535.                       JMP     OverflowHandler       ; OverflowHandler rufen
  536.     END
  537.   END EtvTimerHeader;
  538. (*$L=*)
  539.  
  540. PROCEDURE KbdEventsInstalled(): BOOLEAN;
  541.   BEGIN
  542.     RETURN IKBDVecInstalled OR EtvTimerVecInstalled OR TRAP2VecInstalled;
  543.   END KbdEventsInstalled;
  544.  
  545. PROCEDURE DeInstallKbdEvents;
  546.  
  547.   VAR SupvHdl: ModeBuf;
  548.  
  549.   BEGIN
  550.     EnterSupervisorMode( SupvHdl);           (* Supervisormodus, da SysVars *)
  551.  
  552.     (* alte Vektoren restaurieren *)
  553.     (* nur restaurieren, wenn DIESES Modul die Vektoren gesetzt hat !!! *)
  554.     IF TRAP2VecInstalled THEN
  555.       remove( Trap2Handler, TRAP2);
  556.       TRAP2VecInstalled:= FALSE;
  557.     END;
  558.     IF IKBDVecInstalled THEN
  559.       remove( IKBDHeader, IKBD);
  560.       IKBDVecInstalled:= FALSE;
  561.     END;
  562.     IF EtvTimerVecInstalled THEN
  563.       remove( EtvTimerHeader, etv_timer);
  564.       EtvTimerVecInstalled:= FALSE;
  565.     END; (* IF *)
  566.  
  567.     (* Conterm zurücksetzen *)
  568.     Conterm:= oldConterm;               (* alten Wert zurückschreiben *)
  569.  
  570.     LeaveSupervisorMode( SupvHdl);                 (* wieder in Usermodus schalten *)
  571.   END DeInstallKbdEvents;
  572.  
  573. PROCEDURE InstallKbdEvents;
  574.  
  575.   VAR SupvHdl: ModeBuf;
  576.       wait: CHAR;
  577.  
  578.   BEGIN
  579.     (* Puffer syncronisieren *)
  580.     SyncBuffer;
  581.     FlushKbd;
  582.  
  583.     EnterSupervisorMode( SupvHdl);           (* Supervisormodus, da SysVars *)
  584.  
  585.     (* Trap2Handler initialisieren *)
  586.     IF NOT installed( XBRAID, TRAP2) THEN
  587.       install( Trap2Handler, TRAP2);
  588.       TRAP2VecInstalled:= TRUE;
  589.     END;
  590.  
  591.     IF TRAP2VecInstalled THEN
  592.       (* restliche Initialisierungen nur, wenn Trap2Handler installiert *)
  593.  
  594.       (* Conterm setzen *)
  595.       INCL( Conterm, KbShiftBit);         (* Kbshift-Bit setzen *)
  596.  
  597.       (* Überlauf des Tastaturpuffers über BufferKeyPtr verhindern *)
  598.       IF NOT installed( XBRAID, IKBD) THEN
  599.         (* Dazu OverflowHandler über IKBD und... *)
  600.         install( IKBDHeader, IKBD);
  601.         IKBDVecInstalled:= TRUE;
  602.       END;
  603.       IF NOT installed( XBRAID, etv_timer) THEN
  604.         (* etv_timer aufrufen lassen. *)
  605.         install( EtvTimerHeader, etv_timer);
  606.         EtvTimerVecInstalled:= TRUE;
  607.       END;
  608.     END;
  609.     LeaveSupervisorMode( SupvHdl);         (* wieder in Usermodus schalten *)
  610.   END InstallKbdEvents;
  611.  
  612. PROCEDURE Removal;
  613. (*
  614.  * Diese Routine meldet das Modul beim GEM ab. Zuvor müssen die Register
  615.  * restauriert werden.
  616.  *)
  617.   BEGIN
  618.     (* Vektoren restaurieren *)
  619.     DeInstallKbdEvents;
  620.  
  621.     (* Nun zuletzt beim GEM abmelden. Dabei wird jedem Accessory, das auf
  622.      * Message-Events wartet die Nachricht accClose geschickt. Weil die
  623.      * Vektoren restauriert sind, klinken sich die Acc's aus dem Modul aus.
  624.      * Daher kann nun das Modul terminieren.
  625.      *)
  626.     ExitGem (GEMHandle);
  627.  
  628.   END Removal;
  629.  
  630. PROCEDURE InitModule;
  631. (*
  632.  * Modul initialisieren.
  633.  *)
  634.   PROCEDURE InitTrap2PBList;
  635.   (*
  636.    * Initialisiert die PB-Liste. Dazu werden alle PB's über 'Trap2PBFree'
  637.    * verkettet. Außerdem werden die richtigen Anweisungen zum Aufruf von
  638.    * 'afterTrap2' in den PB eingetragen.
  639.    *)
  640.     VAR ListPtr: CARDINAL;
  641.  
  642.     BEGIN
  643.       Trap2PBFree:= ADR( Trap2PBList);  (* Trap2PBFree zeigt auf erstes El. *)
  644.       FOR ListPtr:= 0 TO HighTrap2PBList DO
  645.         WITH Trap2PBList[ ListPtr] DO
  646.           (* Liste über AddrIntOut verketten *)
  647.           AESNo:= 0;                           (* Kennung für freies Element *)
  648.           IF ListPtr < HighTrap2PBList THEN
  649.             AddrINTOUT:= ADR( Trap2PBList[ ListPtr+1])
  650.           ELSE
  651.             AddrINTOUT:= NIL
  652.           END;
  653.           moveToStackInstr:= WORD( MOVEToStackInstr);
  654.           PBAddr:= ADR( Trap2PBList[ ListPtr]);
  655.           jmpInstr:= WORD( JMPInstr);
  656.           AfterTrap2Addr:= ADDRESS( afterTrap2);
  657.         END (* WITH *)
  658.       END; (* FOR *)
  659.     END InitTrap2PBList;
  660.  
  661.   VAR wsp: MemArea;
  662.       SupvHdl: ModeBuf;
  663.       success: BOOLEAN;
  664.  
  665.   BEGIN
  666.     (* zunächst beim GEM anmelden *)
  667.     SysInitApplication ( success);
  668.     IF NOT success THEN
  669.       ASSEMBLER
  670.         TRAP    #6
  671.         DC.W    OutOfMemory
  672.       END;
  673.     END;
  674.     (* GEM-Handle für's abmelden merken *)
  675.     GEMHandle:= CurrGemHandle();
  676.  
  677.     (* Zeiger auf IOREC-Struktur der Tastatur ermitteln *)
  678.     IoRecPtr:= IORec( Keyboard);
  679.  
  680.     (* IbufPlusIbufsize errechnen *)
  681.     WITH IoRecPtr^ DO
  682.       IbufPlusIbufsize:= ibuf + LONG (ibufsize);
  683.     END;
  684.  
  685.     (* Flags für Vektoren initialisieren *)
  686.     TRAP2VecInstalled:= FALSE;
  687.     IKBDVecInstalled:= FALSE;
  688.     EtvTimerVecInstalled:= FALSE;
  689.  
  690.     (* oldConterm initialisieren *)
  691.     EnterSupervisorMode( SupvHdl);               (* Supervisormodus, da SysVar *)
  692.     oldConterm:= Conterm;
  693.     LeaveSupervisorMode( SupvHdl);                     (* wieder User-Modus *)
  694.  
  695.     (* Bei Terminierung deinitialisieren *)
  696.     wsp.bottom:= 0L;
  697.     CatchRemoval( rCarrier, Removal, wsp);
  698.  
  699.     (* Trap2PBList initialisieren *)
  700.     InitTrap2PBList;
  701.   END InitModule;
  702.  
  703. BEGIN
  704.   (* Modul wird nun nicht mehr automatisch aktiv gesetzt !!! *)
  705.   InitModule;
  706. END KbdEvents.
  707.